﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.Windows.Shapes;
using System.Windows.Media;
using WinRTXamlToolkit.Controls;
using System.Windows.Media.Imaging;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework;

namespace NexusCamera
{
    public partial class CameraControl : UserControl
    {
        #region Properties

        public static string _eventExecute = "";

        private System.Windows.Point _position;
        private string[,] _arrayOfEvent;
        private string[,] _arrayOfImagePath;
        private string[] _dictionary;
        private Image[,] _arrayOfImage;
        private int _menuBook = 0;
        private double _size = 1.8;
        private double _miniCircleRadius = 50;
        private double _startAngle = 0;
        private bool _animationCompleted = false;
        private bool _isValidControl = false;
        private string _sound = "";
        private const double PI = 3.14;

        #endregion

        #region Main Menu Properties

        private List<System.Windows.Point> _menuItems = new List<System.Windows.Point>();
        private List<System.Windows.Point> _angleMenuItems = new List<System.Windows.Point>();
        private List<RingSlice> _ringSlice = new List<RingSlice>();
        private int _menuCount = 0;
        private int _maxMenu = 20;
        private double _mainMenuInnerRadius = 105;
        private double _mainMenuRadius = 180;
        
        #endregion

        #region Sub Menu Properties

        private RingSlice[,] _subRingSlice;
        private int[] _subMenuCount;
        private int _subMenuSize = 25;
        private int _maxSubMenu = 5;
        private double _subMenuInnerRadius = 105;
        private double _subMenuRadius = 220;
        
        #endregion

        #region Get set value

        public string EventExecute
        {
            get { return _eventExecute; }
        }

        public double MainMenuRadius
        {
            get { return _mainMenuRadius; }
            set
            {
                if (value < _mainMenuInnerRadius + 25)
                    _mainMenuRadius = _mainMenuInnerRadius + 25;
                else
                    _mainMenuRadius = value;
            }
        }

        public System.Windows.Point Position
        {
            get { return _position; }
            set { _position = value; }
        }

        public Double Size
        {
            get { return _size; }
            set { _size = value; }
        }

        public string Sound
        {
            get { return _sound; }
            set { _sound = value; }
        }

        public double StartAngle
        {
            get { return _startAngle; }
            set { _startAngle = value; }
        }

        public double SubMenuRadius
        {
            get {
                if (_subMenuRadius < _mainMenuRadius + 25)
                    return _mainMenuRadius + 25;
                else
                    return _subMenuRadius;
            }
            set
            {
                if (value < _mainMenuRadius)
                    _subMenuRadius = _mainMenuRadius + 20;
                else
                    _subMenuRadius = value;
            }
        }

        #endregion

        public void AddMainMenu(string menuName, int menuSize, string imagePath)
        {
            try
            {
                // Cek Nama Main Menu Tidak Boleh Kosong
                if (IsMenuEmpty(menuName))
                {
                    //MessageBox.Show("Nama main menu tidak boleh kosong");
                    MessageBox.Show("MainMenu Name cannot be null");
                    return;
                }

                // Cek Nama Menu Tidak Boleh Sama Satu Sama Lain
                if (IsMenuExist(menuName) != -1)
                {
                    //MessageBox.Show("Menu " + menuName   + " sudah terdaftar");
                    MessageBox.Show("Cannot add menu " + menuName + ", that menu name already registered");
                    return;
                }

                // Cek Menu Size Minimal Adalah 0 
                if (menuSize < 0)
                {
                    //MessageBox.Show("Menu size minimum adalah 0, untuk menu " + menuName + " ukuran menu tidak mencukupi");
                    MessageBox.Show("Menu size minimum is 0, for menu " + menuName + " menu size is too low");
                    return;
                }

                // Input Nama Menu Kedalam Dictionary Nama Menu
                _dictionary[_menuItems.Count()] = menuName;
                // Set Image Menu
                _arrayOfImagePath[_menuItems.Count(), 0] = imagePath;
                // Tambahkan Menu
                _menuItems.Add(new System.Windows.Point(_menuItems.Count(), menuSize));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        public void AddMainMenu(string menuName, int menuSize, string imagePath, string menuEvent)
        {
            try
            {
                int countMenu = _menuItems.Count();
                AddMainMenu(menuName, menuSize, imagePath);
                if (countMenu == _menuItems.Count())
                    return;

                // Set Event Menu
                _arrayOfEvent[countMenu, 0] = menuEvent.Replace(" ", "");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        public void AddSubMenu(string subMenu, string imagePath, string subMenuEvent)
        {
            try
            {
                // Cek Nama Main Menu Dari Sub Menu Yang Dimaksud Tidak Boleh Kosong
                if (IsMenuEmpty(subMenu))
                {
                    //MessageBox.Show("Nama Main Menu Yang Dimaksud Tidak Boleh Kosong");
                    MessageBox.Show("MainMenu name cannot be null");
                    return;
                }

                // Cek Nama Main Menu Harus Sudah Terdaftar
                int i = IsMenuExist(subMenu);
                if (i == -1)
                {
                    MessageBox.Show("Menu " + subMenu + " not registered");
                    return;
                }

                _subMenuCount[i]++;

                _arrayOfImagePath[i, _subMenuCount[i]] = imagePath;

                _arrayOfEvent[i, _subMenuCount[i]] = subMenuEvent.Replace(" ", "");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        public void Calculate()
        {
            CalculateInnerRadius();
            if (CheckCondition())
            {
                this._isValidControl = true;
                DrawMainMenu();
                DrawSubMenu();
            }
        }

        private void CalculateInnerRadius()
        {
            _mainMenuInnerRadius = Size * 50 + 5;
            _subMenuInnerRadius = _mainMenuInnerRadius;
        }

        private double CalculateSubMenuAngle(int j)
        {
            double lastAngle = 0;
            double MiddleOfMenu = ((_angleMenuItems[j].Y - _angleMenuItems[j].X) / 2) + _angleMenuItems[j].X;
            if (_subMenuCount[j] % 2 == 0)
            {
                return lastAngle = MiddleOfMenu - (_subMenuSize * _subMenuCount[j] / 2);
            }
            else
            {
                return lastAngle = MiddleOfMenu - _subMenuSize / 2 - (_subMenuSize * (_subMenuCount[j] - 1) / 2);
            }
        }

        public CameraControl()
        {
            InitializeComponent();

            _arrayOfEvent = new string[_maxMenu, _maxSubMenu + 1];
            _arrayOfImagePath = new string[_maxMenu, _maxSubMenu + 1];
            _subMenuCount = new int[_maxMenu];
            _dictionary = new string[_maxMenu];
            for (int i = 0; i < _maxMenu; i++)
            {
                for (int k = 0; k < _maxSubMenu + 1; k++)
                {
                    _arrayOfEvent[i, k] = "";
                    _arrayOfImagePath[i, k] = "";
                }
                _subMenuCount[i] = 0; 
                _dictionary[i] = "";
            }
        }

        private bool CheckCondition()
        {
            _menuBook = 0;
            _menuCount = 0;

            foreach (System.Windows.Point m in _menuItems)
            {
                _menuBook += (int)m.Y;
                _menuCount++;
            }

            if (_menuBook > _maxMenu)
            {
                //MessageBox.Show("Total Ukuran Menu Melebihi Batas Maksimal (" + _menuBook + "/" + _maxMenu + ")");
                MessageBox.Show("Menu size more than maximal limit (" + _menuBook + "/" + _maxMenu + ")");
                return false;
            }

            if (_subMenuCount.Max() > _maxSubMenu)
            {
                //MessageBox.Show("Terdapat Sub Menu Melebihi Batas Maksimal (" + _subMenuCount.Max() + "/" + _maxSubMenu + ")");
                MessageBox.Show("There is sub menu count more than maximal limit (" + _subMenuCount.Max() + "/" + _maxSubMenu + ")");
                return false;
            }

            for (int j = 0; j < _menuCount; j++)
            {
                if (_subMenuCount[j] == 1)
                    _subMenuCount[j] = 0;
            }

            return true;
        }

        public void CircleAnimation_Completed(object sender, EventArgs e)
        {
            _animationCompleted = true;

            foreach (RingSlice r in _ringSlice)
            {
                r.Center = new System.Windows.Point(_position.X + 41, _position.Y + 61);
                r.Visibility = System.Windows.Visibility.Visible;
                r.Opacity = 0;
            }

            for (int i = 0; i < _menuCount; i++)
            {
                _arrayOfImage[i, 0].Margin = new Thickness(_position.X + _arrayOfImage[i, 0].MaxWidth / 3
                    + Math.Sin(DegreeToRadian(_angleMenuItems[i].X + (_angleMenuItems[i].Y - _angleMenuItems[i].X) / 2))
                    * (_mainMenuRadius - (_mainMenuRadius - _mainMenuInnerRadius) / 2), _position.Y + _arrayOfImage[i, 0].MaxHeight * 4 / 5
                    - Math.Cos(DegreeToRadian(_angleMenuItems[i].X + (_angleMenuItems[i].Y - _angleMenuItems[i].X) / 2))
                    * (_mainMenuRadius - (_mainMenuRadius - _mainMenuInnerRadius) / 2), 0, 0);
                _arrayOfImage[i, 0].Visibility = System.Windows.Visibility.Visible;
            }
        }

        public void Clear()
        {
            if (!_isValidControl)
                return;

            SetMainMenuVisible(false);
            SetSubMenuVisible(false);
        }

        private double DegreeToRadian(double degree)
        {
            double Radian = 0.0;
            Radian = degree * PI / 180;

            return Radian;
        }

        private void DrawMainMenu()
        {
            double lastAngle = _startAngle;
            _arrayOfImage = new Image[_menuCount, _subMenuCount.Max() + 1];

            foreach (System.Windows.Point m in _menuItems)
            {
                RingSlice ringSlice = new RingSlice();
                ringSlice.Name = "" + (m.X);
                ringSlice.Fill = new SolidColorBrush(Colors.DarkGray);
                //ringSlice.Fill = new SolidColorBrush(Color.FromArgb(255, (byte)(255 - (6 - m.X) * 20), (byte)(255 - m.X * 20), (byte)(m.X * 20)));
                ringSlice.StartAngle = lastAngle;
                lastAngle += (360.0 / _menuBook) * m.Y;
                if (lastAngle >= 360 + _startAngle)
                    lastAngle = 360 + _startAngle - 0.0001;
                ringSlice.EndAngle = lastAngle;
                _angleMenuItems.Add(new System.Windows.Point(ringSlice.StartAngle, ringSlice.EndAngle));
                ringSlice.VerticalAlignment = VerticalAlignment.Top;
                ringSlice.HorizontalAlignment = HorizontalAlignment.Left;
                ringSlice.Radius = _mainMenuRadius;
                ringSlice.InnerRadius = _mainMenuInnerRadius;
                ringSlice.UseLayoutRounding = false;
                ringSlice.Height = LayoutRoot.Height;
                ringSlice.Width = LayoutRoot.Width;
                ringSlice.Visibility = System.Windows.Visibility.Collapsed;
                ringSlice.MouseEnter += MainMenu_MouseEnter;
                ringSlice.MouseLeave += MainMenu_MouseLeave;
                _ringSlice.Add(ringSlice);
                LayoutRoot.Children.Add(ringSlice);

                Image image = new Image();
                image.Name = "" + (m.X);
                image.MaxHeight = 48; image.MaxWidth = 48;
                image.MinHeight = 48; image.MinWidth = 48;
                image.Source = new BitmapImage(new Uri(_arrayOfImagePath[(int)m.X, 0], UriKind.Relative));
                image.Visibility = System.Windows.Visibility.Collapsed;
                image.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                image.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                image.Stretch = Stretch.Fill;
                image.MouseEnter += MainMenu_MouseEnter;
                image.MouseLeave += MainMenu_MouseLeave;
                _arrayOfImage[(int)m.X, 0] = image;
                LayoutRoot.Children.Add(image);
            }
        }

        private void DrawSubMenu()
        {
            double lastAngle = 0;
            _subRingSlice = new RingSlice[_menuCount, _subMenuCount.Max()];

            for (int j = 0; j < _menuCount; j++)
            {
                lastAngle = CalculateSubMenuAngle(j);

                for (int i = 0; i < _subMenuCount[j]; i++)
                {
                    RingSlice ringSlice = new RingSlice();
                    ringSlice.Fill = new SolidColorBrush(Colors.DarkGray);
                    //ringSlice.Fill = new SolidColorBrush(Color.FromArgb(255, 255, (byte)((4 - i) * 50), (byte)(i * 50)));
                    ringSlice.Name = j + "" + i;
                    ringSlice.StartAngle = lastAngle;
                    lastAngle += _subMenuSize;
                    ringSlice.EndAngle = lastAngle;
                    ringSlice.VerticalAlignment = VerticalAlignment.Top;
                    ringSlice.HorizontalAlignment = HorizontalAlignment.Left;
                    ringSlice.Radius = _subMenuRadius;
                    ringSlice.InnerRadius = _subMenuInnerRadius;
                    ringSlice.UseLayoutRounding = false;
                    ringSlice.Height = LayoutRoot.Height;
                    ringSlice.Width = LayoutRoot.Width;
                    ringSlice.Visibility = System.Windows.Visibility.Collapsed;
                    ringSlice.MouseEnter += SubMenu_MouseEnter;
                    ringSlice.MouseLeave += SubMenu_MouseLeave;
                    _subRingSlice[j, i] = ringSlice;
                    LayoutRoot.Children.Add(ringSlice);

                    Image image = new Image();
                    image.Name = j + "" + i;
                    image.MaxHeight = 48; image.MaxWidth = 48;
                    image.MinHeight = 48; image.MinWidth = 48;
                    image.Source = new BitmapImage(new Uri(_arrayOfImagePath[j, i + 1], UriKind.Relative));
                    image.Visibility = System.Windows.Visibility.Collapsed;
                    image.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                    image.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                    image.MouseEnter += SubMenu_MouseEnter;
                    image.MouseLeave += SubMenu_MouseLeave;
                    _arrayOfImage[j, i + 1] = image;
                    LayoutRoot.Children.Add(image);
                }
            }
        }

        private string GetName(object sender)
        {
            var type = sender.GetType();
            if (type.Name == "RingSlice")
                return ((RingSlice)sender).Name;
            else
                return ((Image)sender).Name;
        }

        private bool IsImageExist(int idx)
        {
            if (_arrayOfImagePath[idx, 0] == "")
                return false;
            return true;
        }

        private bool IsMenuEmpty(string menuName)
        {
            if (menuName != "")
                return false;
            else
                return true;
        }

        private int IsMenuExist(string menuName)
        {
            for (int i = 0; i < _maxMenu; i++)
                if (_dictionary[i] == menuName)
                    return i;

            return -1;
        }

        void MainMenu_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            int idx = Int32.Parse(GetName(sender));

            if (!IsImageExist(idx))
                return;

            if (_subMenuCount[idx] != 0)
            {
                double lastAngle = CalculateSubMenuAngle(idx) + _subMenuSize / 2;

                for (int i = 0; i < _subMenuCount[idx]; i++)
                {
                    _subRingSlice[idx, i].Center = new System.Windows.Point(_position.X + 41, _position.Y + 61);
                    _subRingSlice[idx, i].Visibility = System.Windows.Visibility.Visible;
                    _subRingSlice[idx, i].Opacity = 0;

                    _arrayOfImage[idx, i + 1].Margin = new Thickness(_position.X + _arrayOfImage[idx, i + 1].MaxWidth / 3
                        + Math.Sin(DegreeToRadian(lastAngle + i * _subMenuSize))
                        * (_subMenuRadius - (_subMenuRadius - _subMenuInnerRadius) / 2), _position.Y + _arrayOfImage[idx, i + 1].MaxHeight * 4 / 5
                        - Math.Cos(DegreeToRadian(lastAngle + i * _subMenuSize))
                        * (_subMenuRadius - (_subMenuRadius - _subMenuInnerRadius) / 2), 0, 0);
                    _arrayOfImage[idx, i + 1].Visibility = System.Windows.Visibility.Visible;
                }
                SetMainMenuVisible(false);
            }
            else
            {
                if (sender.GetType().Name == "RingSlice")
                    PlaySound(_sound);

                _ringSlice[idx].Opacity = 1;

                _eventExecute = _arrayOfEvent[idx, 0];
            }
        }

        void MainMenu_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            int idx = Int32.Parse(GetName(sender));

            if (!IsImageExist(idx))
                return;

            _ringSlice[idx].Opacity = 0;

            _eventExecute = "";
        }

        private void Menu_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            try
            {
                if (_animationCompleted == true)
                {
                    SetMainMenuVisible(true);
                    SetSubMenuVisible(false);
                }

                _eventExecute = "";
            }
            catch (Exception)
            {
            }
        }

        private void PlaySound(string path)
        {
            try
            {
                if (!string.IsNullOrEmpty(path))
                {
                    using (var stream = TitleContainer.OpenStream(path))
                    {
                        if (stream != null)
                        {
                            var effect = SoundEffect.FromStream(stream);
                            FrameworkDispatcher.Update();
                            effect.Play();
                        }
                    }
                }
            }
            catch (Exception ex)
            { }
        }

        public void SetMainMenuVisible(bool isVisible)
        {
            foreach (RingSlice r in _ringSlice)
            {
                if (isVisible)
                    r.Visibility = System.Windows.Visibility.Visible;
                else
                    r.Visibility = System.Windows.Visibility.Collapsed;
            }
            for (int i = 0; i < _menuCount; i++)
            {
                if (isVisible)
                    _arrayOfImage[i, 0].Visibility = System.Windows.Visibility.Visible;
                else
                    _arrayOfImage[i, 0].Visibility = System.Windows.Visibility.Collapsed;
            }
        }

        public void SetSubMenuVisible(bool isVisible)
        {
            for (int i = 0; i < _menuCount; i++)
            {
                for (int j = 0; j < _subMenuCount[i]; j++)
                {
                    if (isVisible)
                    {
                        _subRingSlice[i, j].Visibility = System.Windows.Visibility.Visible;
                        _arrayOfImage[i, j + 1].Visibility = System.Windows.Visibility.Visible;
                    }
                    else
                    {
                        _subRingSlice[i, j].Visibility = System.Windows.Visibility.Collapsed;
                        _arrayOfImage[i, j + 1].Visibility = System.Windows.Visibility.Collapsed;
                    }
                }
            }
        }

        public void Start(System.Windows.Point position)
        {
            if (!_isValidControl)
            {
                this.Visibility = System.Windows.Visibility.Collapsed;
                return;
            }

            _position = new System.Windows.Point(position.X - _miniCircleRadius, position.Y - _miniCircleRadius);
            Menu.Margin = new Thickness(_position.X, _position.Y, 0, 0);
            _animationCompleted = false;
            circleAnimation.Begin();
            circleAnimation.Completed += CircleAnimation_Completed;

            SetMainMenuVisible(false);
        }

        void SubMenu_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (sender.GetType().Name == "RingSlice")
                PlaySound(_sound);

            string id = GetName(sender);

            int idx = Int32.Parse(id.Substring(0, id.Count() - 1));
            int idy = Int32.Parse(id.Substring(id.Count() - 1, 1));

            _subRingSlice[idx, idy].Opacity = 1;
            _eventExecute = _arrayOfEvent[idx, idy + 1];
        }

        void SubMenu_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            string id = GetName(sender);

            int idx = Int32.Parse(id.Substring(0, id.Count() - 1));
            int idy = Int32.Parse(id.Substring(id.Count() - 1, 1));

            _subRingSlice[idx, idy].Opacity = 0;

            _eventExecute = "";
        }
    }
}
